﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using BasicFramework.Entities;
using BasicFramework.Factory;

namespace BasicFramework.Components
{
    public abstract class Component : IComponent
    {

        #region Fields

        private int drawOrder;
        private bool enabled;
        private int updateOrder;
        private IEntity owner;
        private bool visible;
        private bool disposed;
        /// <summary>
        /// Indicates wether the Components is updated for the first time
        /// </summary>
        private bool firstUpdate = true;

        #endregion


        #region Properties





        #endregion


        #region Constructors


        #endregion


        #region Events

        public event EventHandler<EventArgs> EnabledStateChanged;
        public event EventHandler<EventArgs> OwnerChanged;
        public event EventHandler<EventArgs> DrawOrderChanged;
        public event EventHandler<EventArgs> VisibleStateChanged;
        public event EventHandler<EventArgs> UpdateOrderChanged;

        #endregion

        #region Methods

        public virtual void LoadResources(bool loadAllContent)
        { }
        public virtual void UnloadResources(bool unloadAllContent)
        { }

        public virtual void Draw(float frame)
        { }

        public virtual void Start()
        {
        }

        public virtual void Update(float frame)
        {
            if (this.firstUpdate)
            {
                //this.Start();
                this.firstUpdate = false;
            }
        }



        public virtual void OnEnabledStateChanged()
        {
            if (this.EnabledStateChanged != null)
            {
                this.EnabledStateChanged(this, EventArgs.Empty);
            }
        }

        public virtual void OnOwnerChanged()
        {
            if (this.OwnerChanged != null)
            {
                this.OwnerChanged(this, EventArgs.Empty);
            }
        }

        public virtual void OnDrawOrderChanged()
        {
            if (this.DrawOrderChanged != null)
            {
                this.DrawOrderChanged(this, EventArgs.Empty);
            }
        }


        public virtual void OnUpdateOrderChanged()
        {
            if (this.UpdateOrderChanged != null)
            {
                this.UpdateOrderChanged(this, EventArgs.Empty);
            }
        }


        public virtual void OnVisibleStateChanged()
        {
            if (this.VisibleStateChanged != null)
            {
                this.VisibleStateChanged(this, EventArgs.Empty);
            }
        }

        #endregion

        #region IComponent Members


        public IEntity Owner
        {
            get { return this.owner; }
            set
            {
                if (this.owner != value)
                {
                    this.owner = value;
                    this.OnOwnerChanged();
                }
            }
        }

        public int DrawOrder
        {
            get
            {
                return this.drawOrder;
            }
            set
            {
                if (value != this.drawOrder)
                {
                    this.drawOrder = value;
                    this.OnDrawOrderChanged();
                }
            }
        }

        int IComponent.UpdateOrder
        {
            get { return this.updateOrder; }
            set
            {
                if (this.updateOrder != value)
                {
                    this.updateOrder = value;
                    this.OnUpdateOrderChanged();
                }
            }
        }

        bool IComponent.Visible
        {
            get { return this.visible; }
            set
            {
                if (value != this.visible)
                {
                    this.visible = value;
                    this.OnVisibleStateChanged();
                }
            }
        }

        public bool Enabled
        {
            get
            {
                return this.enabled;
            }
            set
            {
                if (this.enabled != value)
                {
                    this.enabled = value;
                    this.OnEnabledStateChanged();
                }
            }
        }

        public virtual void Initialize(bool createDependencies)
        {
            this.Enabled = true;
            this.visible = true;

            if (createDependencies)
            {
                // Get all Component Attributes
                object[] attributes = this.GetType().GetCustomAttributes(true);

                foreach (object obj in attributes)
                {
                    // Check if DependencyAttribute is used
                    if (obj is ComponentDependency)
                    {
                        ComponentDependency cd = obj as ComponentDependency;

                        // Get all Dependend types
                        foreach (Type t in cd.Dependencies)
                        {
                            // Get Interfaces of dependend type
                            Type[] interfaces = t.GetInterfaces();

                            foreach (Type dependendInterface in interfaces)
                            {
                                // Check if depend type implements IEntityComponent interface
                                if (dependendInterface.ToString().Equals(Properties.Resource.ComponentInterfaceName, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    ComponentFactory.Create(t, this.owner, false);

                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }



        #endregion

        #region IDisposable Members



        protected virtual void Dispose(Boolean disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.

                }

                // Release unmanaged resources. If disposing is false, 
                // only the following code is executed.

            }
            disposed = true;
        }



        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
